package net.homelinux.chaoswg.io.renga.krypto.idea;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import net.homelinux.chaoswg.io.higherorderfunctions.AbstractUnaryFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.UnaryFunction;
import net.homelinux.chaoswg.io.renga.krypto.datatypes.numerical.Unsigned128Bit;
import net.homelinux.chaoswg.io.renga.krypto.datatypes.numerical.Unsigned16Bit;
import net.homelinux.chaoswg.io.renga.krypto.datatypes.numerical.UnsignedNBit;

public class IDEAKeySchedule extends AbstractUnaryFunction<List<UnsignedNBit>, UnsignedNBit> implements UnaryFunction<List<UnsignedNBit>, UnsignedNBit> {

    BigInteger splicer = new BigInteger ("2").pow (16).subtract (new BigInteger ("1"));

    public List<UnsignedNBit> apply (UnsignedNBit unb) {
        Unsigned128Bit u128b = ((Unsigned128Bit)unb);
        
        List<UnsignedNBit> toReturn = new Vector<UnsignedNBit>();
        BigInteger u128bval = u128b.getValue();
        for (int i = 0, n = 8; i < n; ++i) {
            toReturn.addAll (Arrays.asList(slice(u128bval)));
            u128bval = rotate (u128bval);
        }
        toReturn.remove (63);
        toReturn.remove (62);
        toReturn.remove (61);
        toReturn.remove (60);

        return toReturn;
    }

    private BigInteger rotate (BigInteger bi) {
        // i << 25 | i >> 103
        return new BigInteger ("340282366920938463463374607431768211455").and(bi.shiftLeft(25).or(bi.shiftRight(103)));
    }

    private UnsignedNBit [] slice (BigInteger tmp) {
        BigInteger u128bVal = new BigInteger (tmp.toString());

        UnsignedNBit[] toReturn = new UnsignedNBit [8];

        for (int i = 0; i < toReturn.length; ++i) {
            toReturn[toReturn.length - i - 1] = new Unsigned16Bit ( u128bVal.and(splicer));
            u128bVal = u128bVal.shiftRight (16);
        }

        return toReturn;
    }
    
    public static void main (String... args) {
        
        new IDEAKeySchedule ().apply(new Unsigned128Bit (new BigInteger ("5192455318486707404433266433261576")));
    }
}